package com.itheima.config;

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowItem;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @Author：shenkunlin
 * @date： 2021/7/13 10:30
 * @Description：
 ***/
//@Configuration
public class SentinelConfig {

    @PostConstruct
    private static void initParamFlowRules() {
        ParamFlowRule rule = new ParamFlowRule("iteminfo")
                //参数下标为0
                .setParamIdx(0)
                //限流模式为QPS
                .setGrade(RuleConstant.FLOW_GRADE_QPS)
                //统计窗口时间长度（单位为秒）
                .setDurationInSec(10)
                //流控效果（支持快速失败和匀速排队模式）
                //CONTROL_BEHAVIOR_DEFAULT：限流行为，直接拒绝
                //CONTROL_BEHAVIOR_WARM_UP:限流行为，匀速排队
                //CONTROL_BEHAVIOR_RATE_LIMITER：限流行为，匀速排队
                .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)
                //最大排队等待时长（仅在匀速排队模式生效  CONTROL_BEHAVIOR_RATE_LIMITER）
                //.setMaxQueueingTimeMs(600)
                //最大阈值为10
                .setCount(10);

        // 为特定参数单独设置阈值.
        //如下配置：当下标为0的参数值为tj的时候，阈值到达2的时候则执行限流
        ParamFlowItem item = new ParamFlowItem()
                //参数类型为int类型
                .setClassType(String.class.getName())
                //设置阈值为2
                .setCount(2)
                //需要统计的值
                .setObject(String.valueOf("1"));
        rule.setParamFlowItemList(Collections.singletonList(item)); //返回的是不可变的集合，但是这个长度的集合只有1，可以减少内存空间
        //加载热点数据
        ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
    }

    /***
     * 系统自我保护
     */
    //@PostConstruct
    private void initSystemRule() {
        //系统自我保护集合
        List<SystemRule> rules = new ArrayList<>();
        //创建系统自我保护规则
        SystemRule rule = new SystemRule();
        //CPU使用率 值为0-1,-1 (不生效)
        rule.setHighestCpuUsage(0.3);
        //所有入口资源的 QPS,-1 (不生效)
        rule.setQps(10);
        //入口流量的最大并发数,-1 (不生效)
        rule.setMaxThread(5);
        //所有入口流量的平均响应时间,单位：秒,-1 (不生效)
        rule.setAvgRt(5);
        //将规则加入到集合
        rules.add(rule);
        SystemRuleManager.loadRules(rules);
    }


    /***
     * 熔断降级规则
     */
    //@PostConstruct
    private void initDegradeRule() {
        //降级规则集合
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        //降级规则对象
        DegradeRule rule = new DegradeRule();
        //设置资源
        rule.setResource("iteminfo");
        //设置触发流控熔断阈值(异常数最小值为5，设置的阈值需要大于5)
        // DEGRADE_GRADE_RT模式，单位为ms
        // DEGRADE_GRADE_EXCEPTION_RATIO模式，值在0-1之间
        // DEGRADE_GRADE_EXCEPTION_COUNT模式，值>=5
        //rule.setCount(4);
        //rule.setCount(0.5);
        rule.setCount(100);//RT模式，平均响应时间超过100毫秒，则触发熔断
        //熔断降级策略，支持慢调用比例/异常比例/异常数策略
        //DEGRADE_GRADE_EXCEPTION_RATIO:异常比例数量
        //DEGRADE_GRADE_EXCEPTION_COUNT:异常数
        //DEGRADE_GRADE_RT:平均响应时间
        //rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT); //最低请求次数 5/s
        //rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); //最低请求次数 5/s
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); //保存60s数据后，再对每秒数据进行熔断判断
        //熔断窗口时长，单位为 s
        rule.setTimeWindow(20);
        //将规则添加到集合中
        rules.add(rule);
        //加载规则
        DegradeRuleManager.loadRules(rules);
    }

    /***
     * 限流规则
     */
    //@PostConstruct
    public void initFlowRules(){
        //1.创建存储规则的集合
        List<FlowRule> rules = new ArrayList<FlowRule>();

        //2.创建每个规则的详细规则信息
        FlowRule rule = new FlowRule("iteminfo");
        //阈值
        rule.setCount(2);
        //rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//QPS限流模式
        rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);//线程数量

        //3.将规则添加到集合中
        rules.add(rule);

        //4.将规则集合加载到程序中
        FlowRuleManager.loadRules(rules);
    }
}
